<!DOCTYPE html>
<html>
	<head>
		<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
		<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
		<script type='text/javascript' src="knockout-2.1.0.js"></script>
		<script type="text/javascript">
			//<![CDATA[
var m;
$(function() {

	function trackerViewModel() {
		var self = this;
		self.trips = ko.observableArray([]);
		self.rate = ko.observable(0);
		var bounds = new google.maps.LatLngBounds();
		var _map = new google.maps.Map (
			document.getElementById("map_canvas"),
			{
				zoom: 4,
				center: new google.maps.LatLng(37.09024, -95.712891),
				mapTypeId: google.maps.MapTypeId.ROADMAP,
				disableDefaultUI : true
			}
		);
		m = _map;
		var _markerStart;
		var _markerStop;
		var _latLngStart;
		var _latLngStop;

		self.updateRate = function(ratePosition) {
			self.rate(ratePosition);
			var newValue = 1 / Math.pow(2, ratePosition) * 1000;
			for(var i = 0; i < self.trips().length; ++i) {
				self.trips()[i].PlayRate = newValue;
			}
		}

		self.addTrip = function(trip) {
			self.trips.push(trip);
		}

		self.play = function() {
			for(var i = 0; i < self.trips().length; ++i) {
				self.trips()[i].play();
			}
		}

		self.togglePoly = function(trip) {
			trip.togglePoly();
		}
		
		self.handleFiles = function(files) {
			for (var i = 0; i < files.length; ++i) {
				var trip = new tgd.Tools.Tracker.Trip(_map, files[i], function(t) {
					self.addTrip(t);
					t.PlayRate = self.rate();

					t.Path.forEach(function (element, index) {
						bounds.extend(element);
					});

					if (_markerStart === undefined) {
						_markerStart = new google.maps.Marker({ clickable:false, draggable:true, position: t.Path.getAt(0), map:_map });
						_markerEnd = new google.maps.Marker({ clickable:false, draggable:true, position: t.Path.getAt(t.Path.getLength() - 1), map:_map});
						_latLngStart = t.Path.getAt(0);
						_latLngStop = t.Path.getAt(t.Path.getLength() - 1);

						google.maps.event.addListener(_markerStart, "drag", function(data) {
							for(var i = 0; i < self.trips().length; ++i) {
								self.trips()[i].setStart(data.latLng);
							}
						});

						google.maps.event.addListener(_markerStart, "dragend", function(data) {
							_latLngStart = data.latLng;
							//TODO have to get a cleaner way for the updates to be pushed to UI.
							
							for(var i = 0; i < self.trips().length; ++i) {
								self.trips()[i].setStart(_latLngStart);
							}

							for(var i = 0; i < self.trips().length; ++i) {
								self.trips.push(self.trips.shift());
							}

							self.trips().sort(function(left, right) {
								return left.Seconds - right.Seconds;
							});
							self.trips.valueHasMutated();
							
							bounds = new google.maps.LatLngBounds();
							bounds.extend(_latLngStart);
							bounds.extend(_latLngStop);
							_map.fitBounds(bounds);
						});

						google.maps.event.addListener(_markerEnd, "drag", function(data) {
							for(var i = 0; i < self.trips().length; ++i) {
								self.trips()[i].setEnd(data.latLng);
							}
						});

						google.maps.event.addListener(_markerEnd, "dragend", function(data) {
							_latLngStop = data.latLng;
							//TODO have to get a cleaner way for the updates to be pushed to UI.
							
							for(var i = 0; i < self.trips().length; ++i) {
								self.trips()[i].setEnd(_latLngStop);
							}

							for(var i = 0; i < self.trips().length; ++i) {
								self.trips.push(self.trips.shift());
							}

							self.trips().sort(function(left, right) {
								return left.Seconds - right.Seconds;
							});
							self.trips.valueHasMutated();
						});
					}

					t.setStart(_latLngStart);
					t.setEnd(_latLngStop);
					_map.fitBounds(bounds);
				});
			}
		}
		
		//DRAG AND DROP STUFF
		var dropbox;
		function dragenter(e) { e.stopPropagation(); e.preventDefault(); }
		function dragover(e) { e.stopPropagation(); e.preventDefault(); }
		function drop(e) { e.stopPropagation(); e.preventDefault(); var dt = e.dataTransfer; var files = dt.files; self.handleFiles(files); }
		dropbox = document.getElementById("sidebar");
		dropbox.addEventListener("dragenter", dragenter, false);
		dropbox.addEventListener("dragover", dragover, false);
		dropbox.addEventListener("drop", drop, false);
	}

	var obj = new trackerViewModel();
	ko.applyBindings(obj);

	var img;
	var view;
	var _map;

	var _trips;
	var _tripViewers;

	var points;  //mvc array of lat longs
	var polyopts;
	var poly;

});



var tgd = tgd || {};
tgd.Tools = tgd.Tools || {};
tgd.Tools.Tracker = tgd.Tools.Tracker || {};

tgd.Tools.Tracker.Trip = function (map, file, callback) {
	var self = this;

	if (tgd.Tools.Tracker.Trip.InstanceNumber === undefined) {
		tgd.Tools.Tracker.Trip.InstanceNumber = 0;
	}
	var _num = tgd.Tools.Tracker.Trip.InstanceNumber++;

	this.getColor = function() {
		var hue = _num * 95;
		return "hsl(" + hue + ", 100%, 50%)";
	}

	var _map = map;
    var _points = new google.maps.MVCArray();
    var _times = new google.maps.MVCArray();  //# of seconds since starting to reach the current point
    var _poly = new google.maps.Polyline();
	var _playbackRate = 1000;  //playback milliseconds / realtime second
	var _startTime;
	var _name = file.name;
	var _timeout = null;  //return value from setTimeout
	var _startPositionIdx; //the position on this trip's path that is designated as the beginning for calculations
	var _endPositionIdx; //the position on this trip's path that is designated as the ending for calculations
	var _playMarker = new google.maps.Marker({
		map: _map,
		icon: {
			path : google.maps.SymbolPath.CIRCLE,
			scale: 4,
			fillColor: self.getColor(),
			fillOpacity: 1,
			strokeWeight: 1,
			strokeColor: "#000",
			strokeOpacity: 1
		}
	});
	var _startMarker = new google.maps.Marker({
		map: _map,
		icon: {
			path : google.maps.SymbolPath.CIRCLE,
			scale: 2,
			strokeColor: self.getColor(),
			strokeOpacity: 1
		}
	});
	var _endMarker = new google.maps.Marker({
		map: _map,
		icon: {
			path : google.maps.SymbolPath.CIRCLE,
			scale: 2,
			strokeColor: self.getColor(),
			strokeOpacity: 1
		}
	});

    this.__defineGetter__("Path", function() { return _points; });
    this.__defineGetter__("Times", function() { return _times; });
	this.__defineGetter__("Name", function() { return _name; });
	this.__defineGetter__("Seconds", function() { return (_times.getAt(_endPositionIdx) - _times.getAt(_startPositionIdx)) ; });
	this.__defineSetter__("PlayRate", function(val) { _playbackRate = val; });

	this.getTime = function() {
		var diff = _times.getAt(_endPositionIdx) - _times.getAt(_startPositionIdx);
		var minutes = Math.floor(diff / 60);
		var seconds = (diff - (minutes * 60)) % 60;
		return (minutes > 0 ? minutes + " minutes  " : "") + seconds + " seconds";
	}

	this.togglePoly = function() {
		 _poly.setVisible(!_poly.getVisible());
	}

	this.setStart = function(latLng) {
		var nearest = _points.getAt(0);
		var min = Infinity;
		var temp;

		_points.forEach(function (element, index) {
			if ((temp = (Math.pow(latLng.lat() - element.lat(), 2) + Math.pow(latLng.lng() - element.lng(), 2))) < min) {
				nearest = element;
				min = temp;
				_startPositionIdx = index;
			}
		});

		//TODO it is possible to set the start after end, do I care?
		_startMarker.setPosition(nearest);
	}

	this.setEnd = function(latLng) {
		var nearest = _points.getAt(0);
		var min = Infinity;
		var temp;

		_points.forEach(function (element, index) {
			if ((temp = (Math.pow(latLng.lat() - element.lat(), 2) + Math.pow(latLng.lng() - element.lng(), 2))) < min) {
				nearest = element;
				min = temp;
				_endPositionIdx = index;
			}
		});

		_endPosition = nearest;
		_endMarker.setPosition(nearest);
	}

    this.play = function() {
		_timeout = clearTimeout(_timeout);
		var _cur = _startPositionIdx;

		var runTimer = function() {
			_playMarker.setPosition(_points.getAt(_cur));

			if (_cur < _endPositionIdx) {
				_timeout = setTimeout(runTimer, (_times.getAt(_cur + 1) - _times.getAt(_cur)) * _playbackRate);
			} else {
				_timeout = clearTimeout(_timeout);
			}

            ++_cur;  //increment for next point
		};
		_timeout = setTimeout(runTimer, 32);
		
    }

    //http://www.html5rocks.com/en/tutorials/file/dndfiles/
    var reader = new FileReader();
    reader.onloadend = (function(theFile) {
        return function(e) {
            $($.parseXML(reader.result)).find("Trackpoint").each(function(index) {
                var p = $(this).find("Position").children();
                _points.push(new google.maps.LatLng($(p[0]).text(), $(p[1]).text()));
                if (_startTime === undefined) {
                    _startTime = new Date($($(this).find("Time")).text()).getTime();
                }
                _times.push((new Date($($(this).find("Time")).text()).getTime() - _startTime) / 1000);
            });

			_poly.setOptions({
				path : _points,
				strokeWeight : 2,
				strokeColor : self.getColor(),
				strokeOpacity : 1,
				map : _map
			});

			_poly.setVisible(false);

			callback(self);
        };
    })(file);
    reader.readAsText(file);
}

    //]]>
		</script>
		<style type="text/css">
			html,body{height:100%;margin:0;padding:0;}
			#map_canvas{height:100%;width:80%;position:fixed;top:0;bottom:0;left:0;right: 20%;}

			#sidebar{background:#666;position:fixed;top:0;bottom:0;right:0;left:80%;}
			#sidebar:-moz-drag-over{background: #33B5E5;}

			#menubar{background:#000;border-bottom:solid 1px #666;}
			#menubar input{margin: 5px 10px;background:#09c;border:1px solid #33B5E5;color:#000;font-size:1em;vertical-align:middle;height:30px;width:30px;}
			#btnAdd{float:right;}

			#menurate{background:#333;border-bottom:solid 1px #999;padding:5px;}
			#menurate input{margin:0;background:#666;border:none;color:#ccc;font-size:.6em;padding:0;}
			#menurate input:hover{background:#33B5E5;}
			#menurate input.selected{background:#09c;color:#000;}

			#trips{color:#fff;}
			.trip{padding:10px;border-bottom:solid 1px #999;}
			.trip:last-child{border:none;}
			.trip:hover{background:#999;}
			.color{width:1em;height:1em;float:left;margin-right:5px;}
		</style>
	</head>
	<body>
		<div id="sidebar">
			<div id="menubar">
				<input type="button" id="btnPlay" value="&#x25B6;" data-bind="click: play" />
				<input type="button" id="btnAdd" value="+" onclick="$('#fu').click();" />
				<input type="file" id="fu" data-bind="event: {change: function(data, event) { handleFiles(event.target.files);} }"  multiple="multiple" />
			</div>
			<div id="menurate">
				<input type="button" value=".5x" data-bind="click: function(){updateRate(-1);}, css: {selected: rate() === -1}" />
				<input type="button" value="1x" data-bind="click: function(){updateRate(0);}, css: {selected: rate() === 0}" />
				<input type="button" value="2x" data-bind="click: function(){updateRate(1);}, css: {selected: rate() === 1}" />
				<input type="button" value="4x" data-bind="click: function(){updateRate(2);}, css: {selected: rate() === 2}" />
				<input type="button" value="8x" data-bind="click: function(){updateRate(3);}, css: {selected: rate() === 3}" />
				<input type="button" value="16x" data-bind="click: function(){updateRate(4);}, css: {selected: rate() === 4}" />
				<input type="button" value="32x" data-bind="click: function(){updateRate(5);}, css: {selected: rate() === 5}" />
				<input type="button" value="64x" data-bind="click: function(){updateRate(6);}, css: {selected: rate() === 6}" />
			</div>
			<div id="trips" data-bind="foreach: trips">
				<div class="trip" data-bind="click: $parent.togglePoly, event: {mouseover: $parent.togglePoly, mouseout: $parent.togglePoly}">
					<div class="color" data-bind="style: {background: getColor()}"></div>
					<span data-bind="text: Name"></span>
					<span data-bind="text: getTime()"></span>
				</div>
			</div>
		</div>
		<div id="map_canvas">
		</div>
	</body>
</html>
